#include <gmock/gmock.h>
#include "onvifToolClass.h"
#include <vector>
#include <thread>
#include <json/json.hpp>
#include <iostream>
using namespace std;
using namespace testing;
using nlohmann::json;
using std::string;

#define DEVICE_SERVICE "http://172.16.34.91/onvif/device_service"
#define MEDIA_SERVICE "http://172.16.34.91/onvif/media_service"
#define MEDIA2_SERVICE "http://172.16.34.91/onvif/media2_service"
#define DEVICEIO_SERVICE "http://172.16.34.91/onvif/deviceio_service"
#define PTZ_SERVICE "http://172.16.34.91/onvif/ptz_service"
#define RECORDING_SERVICE "http://172.16.34.91/onvif/recording_service"
#define SEARCH_SERVICE "http://172.16.34.91/onvif/search_service"
#define REPLAY_SERVICE "http://172.16.34.91/onvif/replay_service"
#define PROVISIONING_SERVICE "http://172.16.34.91/onvif/provisioning_service"
#define IMAGING_SERVICE "http://172.16.34.91/onvif/imaging_service"
#define USER_NAME "admin2"
#define PASSWORD "Tisson@123!"

class onvifToolTest : public Test
{
public:
  void SetUp() override
  {
    if (auto err = onvif.init(); err)
    {
      cout << "onvifTool init err: " << *err << endl;
    }
  }

  onvifTool onvif;
};

TEST_F(onvifToolTest, discoverDevice)
{
  string jsonResponse;
  auto err = onvif.discoverDevice(jsonResponse);
  ASSERT_THAT(err, nullopt);

  cout << "deviceLists: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, listenHelloAndBye)
{
  auto err = onvif.listenHello([](string jsonResponse, void *pUserData) -> void
                               { printf("监听到了 hello消息, 有新设备接入, 设备信息: %s\n", jsonResponse.c_str()); },
                               nullptr);
  ASSERT_THAT(err, nullopt);
  err = onvif.listenBye([](string jsonResponse, void *pUserData) -> void
                        { printf("监听到了 bye消息, 有设备退出, 设备信息: %s\n", jsonResponse.c_str()); },
                        nullptr);
  ASSERT_THAT(err, nullopt);

  this_thread::sleep_for(std::chrono::seconds(10));
  err = onvif.stopListenBye();
  ASSERT_THAT(err, nullopt);
  err = onvif.stopListenHello();
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getDeviceInformation)
{
  string jsonResponse;

  auto err = onvif.getDeviceInformation(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "devInfo: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getServices)
{
  string jsonResponse;

  auto err = onvif.getServices(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "services: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getServiceCapabilities)
{
  string jsonResponse;

  auto err = onvif.getServiceCapabilities(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "services Capabilities: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getDNS)
{
  string jsonResponse;

  auto err = onvif.getDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "DNS: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getDynamicDNS)
{
  string jsonResponse;

  auto err = onvif.getDynamicDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "DynamicDNS: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getEndpointReference)
{
  string jsonResponse;

  auto err = onvif.getEndpointReference(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "getEndpointReference: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getGeoLocation)
{
  string jsonResponse;

  auto err = onvif.getGeoLocation(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getGeoLocation: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getNetworkDefaultGateway)
{
  string jsonResponse;

  auto err = onvif.getNetworkDefaultGateway(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getNetworkDefaultGateway: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getNetworkInterfaces)
{
  string jsonResponse;

  auto err = onvif.getNetworkInterfaces(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getNetworkInterfaces: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getNetworkProtocols)
{
  string jsonResponse;

  auto err = onvif.getNetworkProtocols(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getNetworkProtocols: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getHostname)
{
  string jsonResponse;

  auto err = onvif.getHostname(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "getHostname: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getRemoteUser)
{
  string jsonResponse;

  auto err = onvif.getRemoteUser(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getRemoteUser: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getScopes)
{
  string jsonResponse;

  auto err = onvif.getScopes(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getScopes: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getUsers)
{
  string jsonResponse;

  auto err = onvif.getUsers(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getUsers: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getWsdlUrl)
{
  string jsonResponse;

  auto err = onvif.getWsdlUrl(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "getWsdlUrl: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getDiscoveryMode)
{
  string jsonResponse;

  auto err = onvif.getDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getDiscoveryMode: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getRemoteDiscoveryMode)
{
  string jsonResponse;

  auto err = onvif.getRemoteDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getRemoteDiscoveryMode: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, setDNS)
{
  string jsonResponse;
  string oldResopnse;

  // 获取修改前信息
  auto err = onvif.getDNS(oldResopnse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before set: " << oldResopnse << endl;

  // 设置参数
  ONVIF_SET_DNS_PARAM param;
  param.useDHCP = false;
  param.sizeSearchDomain = 0;
  param.sizeDNSManual = 1;
  ONVIF_IP_ADDR **addr;
  addr = new ONVIF_IP_ADDR *[1];
  addr[0] = new ONVIF_IP_ADDR();
  addr[0]->IPv4Address = (char *)"202.96.128.68";
  addr[0]->IPv4Type = true;
  param.DNSManual = addr;

  // 修改
  err = onvif.setDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after set: " << jsonResponse << endl;

  delete addr[0];
  delete[] addr;
  addr = nullptr;

  // 恢复原来的设置
  json j = json::parse(oldResopnse);
  param.useDHCP = j["fromDHCP"] == "true" ? true : false;
  if (param.useDHCP == false)
  {
    auto manual = j["DNSManual"].get<vector<json>>();
    addr = new ONVIF_IP_ADDR *[manual.size()];
    for (int i = 0; i < (int)manual.size(); i++)
    {
      addr[i] = new ONVIF_IP_ADDR();
      addr[i]->IPv4Address = nullptr;
      addr[i]->IPv6Address = nullptr;
      addr[i]->IPv4Type = manual[i]["type"].get<string>() == "IPv4" ? true : false;
      if (addr[i]->IPv4Type)
      {
        addr[i]->IPv4Address = (char *)manual[i]["IPv4Address"].get<string>().c_str();
      }
      else
      {
        addr[i]->IPv6Address = (char *)manual[i]["IPv6Address"].get<string>().c_str();
      }
    }
  }
  param.DNSManual = addr;
  err = onvif.setDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  if (addr != nullptr)
  {
    auto manual = j["DNSManual"].get<vector<json>>();
    for (int i = 0; i < (int)manual.size(); i++)
    {
      delete addr[i];
    }
    delete[] addr;
    addr = nullptr;
  }
}

TEST_F(onvifToolTest, setDynamicDNS)
{
  string jsonResponse;
  ONVIF_SET_DYNAMIC_DNS_PARAM param;
  param.name = (char *)"new_Name";
  param.TTL = nullptr;
  param.type = nullptr;
  auto err = onvif.setDynamicDNS(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setHostname)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getHostname(oldResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "before setHostname: " << oldResponse << endl;

  // 修改
  err = onvif.setHostname(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, "newName");
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getHostname(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "after setHostname: " << jsonResponse << endl;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  if (j["fromDHCP"].get<string>() == "false")
  {
    err = onvif.setHostname(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, j["name"].get<string>().c_str());
    ASSERT_THAT(err, nullopt);
  }
  else
  {
    err = onvif.setHostnameFromDHCP(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, true);
    ASSERT_THAT(err, nullopt);
    cout << "setHostnameFromDHCP response: " << jsonResponse << endl;
  }
}

TEST_F(onvifToolTest, systemReboot)
{
  string jsonResponse;

  auto err = onvif.systemReboot(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "systemReboot response: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, setHostnameFromDHCP)
{
  string jsonResponse;

  auto err = onvif.getHostname(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "before setHostnameFromDHCP: " << jsonResponse << endl;

  err = onvif.setHostnameFromDHCP(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, true);
  ASSERT_THAT(err, nullopt);
  cout << "setHostnameFromDHCP response: " << jsonResponse << endl;

  json j = json::parse(jsonResponse);
  if (j["rebootNeeded"].get<string>() == "true")
  {
    err = onvif.systemReboot(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
    ASSERT_THAT(err, nullopt);
    cout << "systemReboot response: " << jsonResponse << endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }

  err = onvif.getHostname(jsonResponse, DEVICE_SERVICE);
  ASSERT_THAT(err, nullopt);
  cout << "after setHostnameFromDHCP: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, setUser)
{
  string jsonResponse;

  // 修改密码
  ONVIF_SET_USER_PARAM param = {0};
  int level = 0;
  param.sizeUser = 2;
  param.users = new ONVIF_USER[param.sizeUser];
  param.users[0].userName = (char *)USER_NAME;
  param.users[0].password = (char *)"Tisson@123!22";
  param.users[0].userLevel = &level;

  param.users[1].userName = (char *)"admin3";
  param.users[1].password = (char *)"Tisson@123!";
  param.users[1].userLevel = &level;

  auto err = onvif.setUser(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 使用原密码登录
  err = onvif.getUsers(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_FALSE(err == nullopt);
  cout << "user old password err: " << *err << endl;

  // 使用新密码登录
  err = onvif.getUsers(jsonResponse, DEVICE_SERVICE, USER_NAME, "Tisson@123!22");
  ASSERT_THAT(err, nullopt);
  cout << "after setUser: " << jsonResponse << endl;

  // 恢复原来的设置
  param.users[0].password = (char *)"Tisson@123!";
  err = onvif.setUser(jsonResponse, DEVICE_SERVICE, USER_NAME, "Tisson@123!22", &param);
  ASSERT_THAT(err, nullopt);
  delete param.users;
}

TEST_F(onvifToolTest, setScopes)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getScopes(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setScopes: " << oldResponse << endl;

  // 修改
  ONVIF_SET_SCOPES_PARAM param = {0};
  param.sizeScopes = 1;

  char **scopes;
  scopes = new char *[param.sizeScopes];
  scopes[0] = (char *)"new_Scopes";
  param.scopes = scopes;

  err = onvif.setScopes(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getScopes(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setScopes: " << jsonResponse << endl;

  delete[] scopes;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  int oldScopesCount = 0;
  auto scopeVec = j["scopes"].get<json>();
  for (int i = 0; i < (int)scopeVec.size(); i++)
  {
    if (scopeVec[i]["scopeDef"].get<string>() == "configurable")
    {
      oldScopesCount++;
    }
  }

  scopes = new char *[oldScopesCount];
  param.sizeScopes = oldScopesCount;
  oldScopesCount = 0;
  for (int i = 0; i < (int)scopeVec.size(); i++)
  {
    if (scopeVec[i]["scopeDef"].get<string>() == "configurable")
    {
      scopes[oldScopesCount] = (char *)scopeVec[i]["scopeItem"].get<string>().c_str();
      oldScopesCount++;
    }
  }
  param.scopes = scopes;
  err = onvif.setScopes(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  delete[] scopes;
}

TEST_F(onvifToolTest, setRemoteUser)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getRemoteUser(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setRemoteUser: " << oldResponse << endl;

  // 修改
  ONVIF_SET_REMOTE_USER_PARAM param = {0};
  param.password = (char *)"Tisson@123!";
  param.userName = (char *)"remoteUser";
  param.useDerivedPassword = false;

  err = onvif.setRemoteUser(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getRemoteUser(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setRemoteUser: " << jsonResponse << endl;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  param.password = (char *)j["password"].get<string>().c_str();
  param.userName = (char *)j["username"].get<string>().c_str();
  param.useDerivedPassword = j["useDerivedPassword"].get<string>() == "true" ? true : false;
  err = onvif.setRemoteUser(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setDiscoveryMode)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getDiscoveryMode(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setDiscoveryMode: " << oldResponse << endl;

  // 修改
  err = onvif.setDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, false);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setDiscoveryMode: " << jsonResponse << endl;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  bool enable = j["discoverable"].get<string>() == "true" ? true : false;

  err = onvif.setDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, enable);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setRemoteDiscoveryMode)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getRemoteDiscoveryMode(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setRemoteDiscoveryMode: " << oldResponse << endl;

  // 修改
  err = onvif.setRemoteDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, false);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getRemoteDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setRemoteDiscoveryMode: " << jsonResponse << endl;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  bool enable = j["discoverable"].get<string>() == "true" ? true : false;

  err = onvif.setRemoteDiscoveryMode(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, enable);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setNetworkDefaultGateway)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getNetworkDefaultGateway(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setNetworkDefaultGateway: " << oldResponse << endl;

  // 修改
  char *ipv4Addr[1];
  ipv4Addr[0] = (char *)"192.168.1.1";
  ONVIF_SET_NETWORK_DEFAULT_GATEWAY_PARAM param;
  param.sizeIPv4 = 1;
  param.IPv4Address = ipv4Addr;
  param.sizeIPv6 = 0;
  param.IPv6Address = nullptr;
  err = onvif.setNetworkDefaultGateway(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getNetworkDefaultGateway(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setNetworkDefaultGateway: " << jsonResponse << endl;

  // 恢复原来的设置
  json j = json::parse(oldResponse);
  auto ipv4Vec = j["IPv4Address"].get<vector<string>>();
  auto ipv6Vec = j["IPv6Address"].get<vector<string>>();

  param.sizeIPv4 = ipv4Vec.size();
  param.sizeIPv6 = ipv6Vec.size();

  char **ipv4AddrArr = nullptr;
  char **ipv6AddrArr = nullptr;
  if (ipv4Vec.size() != 0)
  {
    ipv4AddrArr = new char *[ipv4Vec.size()];
    for (int i = 0; i < (int)ipv4Vec.size(); i++)
    {
      ipv4AddrArr[i] = (char *)ipv4Vec[i].c_str();
    }
  }

  if (ipv6Vec.size() != 0)
  {
    ipv6AddrArr = new char *[ipv6Vec.size()];
    for (int i = 0; i < (int)ipv6Vec.size(); i++)
    {
      ipv6AddrArr[i] = (char *)ipv6Vec[i].c_str();
    }
  }

  param.IPv4Address = ipv4AddrArr;
  param.IPv6Address = ipv6AddrArr;

  err = onvif.setNetworkDefaultGateway(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  if (ipv4Vec.size() != 0)
  {
    delete[] ipv4AddrArr;
  }

  if (ipv6Vec.size() != 0)
  {
    delete[] ipv6AddrArr;
  }
}

TEST_F(onvifToolTest, setNetworkInterfaces__ChangeIPv4Addr)
{
  string DEVICE_SERVICE__ = "http://172.16.36.196/onvif/device_service";
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getNetworkInterfaces(oldResponse, DEVICE_SERVICE__.c_str(), USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setNetworkInterfaces: " << oldResponse << endl;

  // 修改
  ONVIF_SET_NETWORK_INTERFACE_PARAM param;
  char **IPv4Address;
  IPv4Address = new char *[1];
  IPv4Address[0] = (char *)"172.16.36.100";

  int IPv4PrefixLen[] = {24};

  param.interfaceToken = (char *)"eth0";
  param.enable = true;
  param.MTU = -1;
  param.link = nullptr;

  param.IPv4Enabled = true;
  param.IPv4DHCP = false;
  param.sizeIPv4 = 1;
  param.IPv4Address = IPv4Address;
  param.IPv4PrefixLen = IPv4PrefixLen;

  param.IPv6Enabled = false;
  param.sizeExtension = 0;
  param.extension = nullptr;

  err = onvif.setNetworkInterfaces(jsonResponse, DEVICE_SERVICE__.c_str(), USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  cout << "setNetworkInterfaces response: " << jsonResponse << endl;

  // 重启
  json j = json::parse(jsonResponse);
  if (j["rebootNeeded"].get<string>() == "true")
  {
    err = onvif.systemReboot(jsonResponse, DEVICE_SERVICE__.c_str(), USER_NAME, PASSWORD);
    ASSERT_THAT(err, nullopt);
    cout << "systemReboot response: " << jsonResponse << endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }
  else
  {
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }

  // 查看修改结果（如果改的是IPv6就没用，登录设备去修改，提示IPv6地址、网关、DNS不能为空，因此应该需要先修改网关和DNS再修改IPv6地址）
  char newServiceAddr[100];
  sprintf(newServiceAddr, "http://%s/onvif/device_service", IPv4Address[0]);
  err = onvif.getNetworkInterfaces(jsonResponse, newServiceAddr, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setNetworkInterfaces: " << jsonResponse << endl;

  // 恢复原来的设置
  j = json::parse(oldResponse);
  auto interfaces = j["interfaces"].get<vector<json>>();
  for (int i = 0; i < (int)interfaces.size(); i++)
  {
    if (strcmp(interfaces[i]["token"].get<string>().c_str(), param.interfaceToken) == 0)
    {
      IPv4Address[0] = (char *)interfaces[i]["IPv4"]["config"]["manual"][0]["address"].get<string>().c_str();
      err = onvif.setNetworkInterfaces(jsonResponse, newServiceAddr, USER_NAME, PASSWORD, &param);
      ASSERT_THAT(err, nullopt);
    }
  }
  delete[] IPv4Address;
}

TEST_F(onvifToolTest, setNetworkInterfaces__ChangeLinkAndMTU)
{
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getNetworkInterfaces(oldResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setNetworkInterfaces: " << oldResponse << endl;

  // 修改
  ONVIF_NETWORK_LINK_CONFIGURATION link;
  link.autoNegotiation = true;
  link.speed = 20;
  link.duplex = 1;

  ONVIF_SET_NETWORK_INTERFACE_PARAM param;
  param.interfaceToken = (char *)"eth0";
  param.enable = true;
  param.MTU = 1000;
  param.link = &link;

  param.IPv4Enabled = false;
  param.IPv6Enabled = false;
  param.extension = nullptr;

  err = onvif.setNetworkInterfaces(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  cout << "setNetworkInterfaces response: " << jsonResponse << endl;

  // 重启
  json j = json::parse(jsonResponse);
  if (j["rebootNeeded"].get<string>() == "true")
  {
    err = onvif.systemReboot(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
    ASSERT_THAT(err, nullopt);
    cout << "systemReboot response: " << jsonResponse << endl;
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }
  else
  {
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }

  // 查看修改结果(MTU没有更改，直接登录设备尝试去修改，结果不能修改，应该是设备原因)
  err = onvif.getNetworkInterfaces(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setNetworkInterfaces: " << jsonResponse << endl;

  // 恢复原来的设置
  j = json::parse(oldResponse);
  auto interfaces = j["interfaces"].get<vector<json>>();
  for (int i = 0; i < (int)interfaces.size(); i++)
  {
    if (strcmp(interfaces[i]["token"].get<string>().c_str(), param.interfaceToken) == 0)
    {
      // 当前用户是admin，修改的是adminSetting
      link.autoNegotiation = interfaces[i]["adminSettings"]["autoNegotiation"] == "true" ? true : false;
      link.duplex = interfaces[i]["adminSettings"]["duplex"] == "full" ? 0 : 1;
      link.speed = std::stoi(interfaces[i]["adminSettings"]["speed"].get<string>());
      param.MTU = std::stoi(interfaces[i]["MTU"].get<string>());
      err = onvif.setNetworkInterfaces(jsonResponse, DEVICE_SERVICE, USER_NAME, PASSWORD, &param);
      ASSERT_THAT(err, nullopt);
    }
  }
}

TEST_F(onvifToolTest, setNetworkProtocols)
{
  string DEVICE_SERVICE__ = "http://172.16.36.196/onvif/device_service";
  string jsonResponse;
  string oldResponse;

  // 获取修改前信息
  auto err = onvif.getNetworkProtocols(oldResponse, DEVICE_SERVICE__.c_str(), USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "before setNetworkProtocols: " << oldResponse << endl;

  // 修改
  ONVIF_SET_NETWORK_PROTOCOLS_PARAM param;
  param.sizeProtocols = 2;

  ONVIF_NETWORK_PROTOCOLS **protocols;
  protocols = new ONVIF_NETWORK_PROTOCOLS *[param.sizeProtocols];
  protocols[0] = new ONVIF_NETWORK_PROTOCOLS;
  protocols[1] = new ONVIF_NETWORK_PROTOCOLS;

  int httpPort[1] = {81};
  protocols[0]->protocolsName = 0; // http
  protocols[0]->enabled = true;
  protocols[0]->sizePort = 1;
  protocols[0]->port = httpPort;

  int httpsPort[1] = {444};
  protocols[1]->protocolsName = 1; // https
  protocols[1]->enabled = false;
  protocols[1]->sizePort = 1;
  protocols[1]->port = httpsPort;

  param.protocols = protocols;

  err = onvif.setNetworkProtocols(jsonResponse, DEVICE_SERVICE__.c_str(), USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 等待服务端口重启
  std::this_thread::sleep_for(std::chrono::seconds(10));

  // 查看修改结果
  char newServiceAddr[100];
  sprintf(newServiceAddr, "http://172.16.36.196:%d/onvif/device_service", httpPort[0]);
  err = onvif.getNetworkProtocols(jsonResponse, newServiceAddr, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "after setNetworkProtocols: " << jsonResponse << endl;

  // 恢复原来的设置
  auto j = json::parse(oldResponse);
  auto protocolVec = j["protocols"].get<vector<json>>();

  delete protocols[0];
  delete protocols[1];
  delete[] protocols;
  protocols = new ONVIF_NETWORK_PROTOCOLS *[protocolVec.size()];

  param.sizeProtocols = protocolVec.size();
  for (int i = 0; i < (int)protocolVec.size(); i++)
  {
    protocols[i] = new ONVIF_NETWORK_PROTOCOLS;
    protocols[i]->enabled = protocolVec[i]["enabled"] == "true" ? true : false;
    protocols[i]->protocolsName = protocolVec[i]["name"] == "http" ? 0 : protocolVec[i]["name"] == "https" ? 1
                                                                                                           : 2;
    auto portVec = protocolVec[i]["ports"].get<vector<int>>();
    protocols[i]->sizePort = portVec.size();
    protocols[i]->port = new int[portVec.size()];
    for (int i_ = 0; i_ < (int)portVec.size(); i_++)
    {
      protocols[i]->port[i_] = portVec[i_];
    }
  }
  param.protocols = protocols;
  err = onvif.setNetworkProtocols(jsonResponse, newServiceAddr, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getVideoSources_V1)
{
  string jsonResponse;

  auto err = onvif.getVideoSources_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSources_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getVideoSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00300";

  auto err = onvif.getVideoSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "token";
  // char profileToken[65] = "token";

  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getVideoSourceConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceModes_V1)
{
  string jsonResponse;

  char videoSourceToken[65] = "VideoSource_1";

  auto err = onvif.getVideoSourceModes_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceModes_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getVideoEncoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00300";

  auto err = onvif.getVideoEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00300";
  // char profileToken[65] = "00300";

  auto err = onvif.getVideoEncoderConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, nullptr, nullptr);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSources_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioSources_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSources_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getAudioSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00300";
  // char profileToken[65] = "00300";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioSourceConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputs_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioOutputs_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputs_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioOutputConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getAudioOutputConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioOutputConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioEncoderConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioEncoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioEncoderConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioEncoderConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getAudioEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioEncoderConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioEncoderConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioEncoderConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioEncoderConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioDecoderConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getAudioDecoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioDecoderConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioDecoderConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getAudioDecoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioDecoderConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioDecoderConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioDecoderConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioDecoderConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMetadataConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getMetadataConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getMetadataConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMetadataConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getMetadataConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMetadataConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMetadataConfigurationOptions_V1)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getMetadataConfigurationOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMetadataConfigurationOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoAnalyticsConfigurations_V1)
{
  string jsonResponse;

  auto err = onvif.getVideoAnalyticsConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoAnalyticsConfigurations_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoAnalyticsConfiguration_V1)
{
  string jsonResponse;

  char configToken[65] = "00000";

  auto err = onvif.getVideoAnalyticsConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoAnalyticsConfiguration_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getProfiles_V1)
{
  string jsonResponse;

  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getProfiles_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getProfile_V1)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[8]["token"].get<string>().c_str());

  // 测试getProfile_V1
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getProfile_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, createProfile_V1)
{
  string jsonResponse;

  char name[65] = "profileName";
  char profileToken[65] = "myProfileToken";

  auto err = onvif.createProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, name, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "createProfile_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getOSDs_V1)
{
  string jsonResponse;

  // char videoSourceConfigToken[65] = "token";
  char *videoSourceConfigToken = nullptr;

  auto err = onvif.getOSDs_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, videoSourceConfigToken);
  ASSERT_THAT(err, nullopt);
  cout << "getOSDs_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getOSD_V1)
{
  string jsonResponse;

  char configToken[65] = "OsdToken_102";

  auto err = onvif.getOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getOSD_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getOSDOptions_V1)
{
  string jsonResponse;

  char videoSourceConfigToken[65] = "00000";

  auto err = onvif.getOSDOptions_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, videoSourceConfigToken);
  ASSERT_THAT(err, nullopt);
  cout << "getOSDOptions_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, createOSD_V1_AND_deleteOSD_V1)
{
  string jsonResponse;

  ONVIF_SET_OSD_PARAM param = {0};
  param.OSDConfigurationToken = (char *)"myOSDToken";

  // 获取VideoSourceConfigurationToken
  auto err = onvif.getVideoSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  string VideoSourceConfigurationToken = configurations[0]["token"].get<string>();

  param.videoSourceConfigurationToken = (char *)VideoSourceConfigurationToken.c_str();
  param.type = 0;
  param.positionType = 2;
  param.positionX = nullptr;
  param.positionY = nullptr;
  param.isPersistentText = nullptr;
  param.textType = 0;
  param.dateFormat = 0;
  param.timeFormat = 0;
  param.fontSize = nullptr;
  param.fontColor = nullptr;
  param.fontTransparent = nullptr;
  param.backgroundColor = nullptr;
  param.backgroundTransparent = nullptr;
  param.plainText = (char *)"my new plain text";
  param.imgPath = nullptr;

  // 创建
  err = onvif.createOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看创建结果
  j = json::parse(jsonResponse);
  string configToken = j["OSDToken"].get<string>();
  err = onvif.getOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "createOSD_V1 result: " << jsonResponse << endl;

  // 删除
  err = onvif.deleteOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);

  err = onvif.getOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_TRUE(err != nullopt);
}

TEST_F(onvifToolTest, setOSD_V1)
{
  string jsonResponse;

  ONVIF_SET_OSD_PARAM param = {0};
  param.OSDConfigurationToken = (char *)"myOSDToken";

  // 获取VideoSourceConfigurationToken
  auto err = onvif.getVideoSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  string VideoSourceConfigurationToken = configurations[0]["token"].get<string>();

  param.videoSourceConfigurationToken = (char *)VideoSourceConfigurationToken.c_str();
  param.type = 0;
  param.positionType = 4;
  float x = 1;
  float y = -0.89;
  param.positionX = &x;
  param.positionY = &y;
  param.isPersistentText = nullptr;
  param.textType = 0;
  param.dateFormat = 0;
  param.timeFormat = 0;
  param.fontSize = nullptr;
  param.fontColor = nullptr;
  param.fontTransparent = nullptr;
  param.backgroundColor = nullptr;
  param.backgroundTransparent = nullptr;
  param.plainText = (char *)"云台通道阿瓦达";
  param.imgPath = nullptr;

  // 新建一个OSD
  err = onvif.createOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看新建结果
  j = json::parse(jsonResponse);
  string configToken = j["OSDToken"].get<string>();
  err = onvif.getOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "before set: " << jsonResponse << endl;

  // 修改
  param.OSDConfigurationToken = (char *)configToken.c_str();
  param.plainText = (char *)"set new plain text";
  err = onvif.setOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "after set: " << jsonResponse << endl;

  // 删除
  err = onvif.deleteOSD_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getStreamUri_V1)
{
  string jsonResponse;
  ONVIF_STREAM_SETUP_PARAM streamSetup;
  streamSetup.streamType = 1;
  streamSetup.transport.protocolsName = 2;
  streamSetup.transport.tunnel = nullptr;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 测试getStreamUri_V1
  err = onvif.getStreamUri_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken, &streamSetup);
  ASSERT_THAT(err, nullopt);
  cout << "getStreamUri_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getSnapshotUri_V1)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 测试getSnapshotUri_V1
  err = onvif.getSnapshotUri_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getSnapshotUri_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, startMulticastStreaming_V1)
{
  string jsonResponse;
  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  err = onvif.startMulticastStreaming_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, stopMulticastStreaming_V1)
{
  string jsonResponse;
  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  err = onvif.stopMulticastStreaming_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, addVideoSourceConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getVideoSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addVideoSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addVideoEncoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getVideoEncoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addVideoEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeVideoEncoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeVideoEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addAudioSourceConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getAudioSourceConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addAudioSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addAudioOutputConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getAudioOutputConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addAudioOutputConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeAudioOutputConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeAudioOutputConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addAudioEncoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getAudioEncoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addAudioEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeAudioEncoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeAudioEncoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addAudioDecoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getAudioDecoderConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addAudioDecoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeAudioDecoderConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeAudioDecoderConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeAudioSourceConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeAudioSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addMetadataConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getMetadataConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addMetadataConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeMetadataConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeMetadataConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addVideoAnalyticsConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getVideoAnalyticsConfigurations_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addVideoAnalyticsConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeVideoAnalyticsConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeVideoAnalyticsConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeVideoSourceConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removeVideoSourceConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, addPTZConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before add" << jsonResponse << endl;

  // 获取configuration
  err = onvif.getPTZConfigurations(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configVec = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configVec.size() > 0);
  auto configToken = configVec[0]["token"].get<string>();

  // 添加
  err = onvif.addPTZConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, configToken.c_str(), profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after add" << jsonResponse << endl;
}

TEST_F(onvifToolTest, removePTZConfiguration_V1)
{
  string jsonResponse;
  char profileToken[65] = "myProfileToken";

  // 获取profile
  auto err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "before remove" << jsonResponse << endl;

  // 移除
  err = onvif.removePTZConfiguration_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);

  // 查看添加结果
  err = onvif.getProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "after remove" << jsonResponse << endl;
}

TEST_F(onvifToolTest, deleteProfile_V1)
{
  string jsonResponse;

  char profileToken[65] = "myProfileToken";

  auto err = onvif.deleteProfile_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "deleteProfile_V1: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getVideoSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getVideoSourceConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceModes_V2)
{
  string jsonResponse;

  char videoSourceToken[65] = "VideoSource_1";

  auto err = onvif.getVideoSourceModes_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceModes_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderInstances_V2)
{
  string jsonResponse;

  char videoSourceConfigurationToken[65] = "VideoSourceToken";

  auto err = onvif.getVideoEncoderInstances_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceConfigurationToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderInstances_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getVideoEncoderConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoEncoderConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getVideoEncoderConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoEncoderConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioSourceConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioOutputConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioOutputConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioEncoderConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioEncoderConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioEncoderConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioEncoderConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioEncoderConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioEncoderConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioDecoderConfigurations_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioDecoderConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioDecoderConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioDecoderConfigurationOptions_V2)
{
  string jsonResponse;

  // char configToken[65] = "00000";
  // char profileToken[65] = "00000";
  char *configToken = nullptr;
  char *profileToken = nullptr;

  auto err = onvif.getAudioDecoderConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioDecoderConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMetadataConfigurations_V2)
{
  string jsonResponse;
  // char profileToken[65] = {0};
  // char configurationToken[65] = {0};
  char *profileToken = nullptr;
  char *configurationToken = nullptr;

  auto err = onvif.getMetadataConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configurationToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMetadataConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMetadataConfigurationOptions_V2)
{
  string jsonResponse;
  // char profileToken[65] = {0};
  // char configurationToken[65] = {0};
  char *profileToken = nullptr;
  char *configurationToken = nullptr;

  auto err = onvif.getMetadataConfigurationOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configurationToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMetadataConfigurationOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAnalyticsConfigurations_V2)
{
  string jsonResponse;
  // char profileToken[65] = {0};
  // char configurationToken[65] = {0};
  char *profileToken = nullptr;
  char *configurationToken = nullptr;

  auto err = onvif.getAnalyticsConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configurationToken, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAnalyticsConfigurations_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getProfiles_V2)
{
  string jsonResponse;
  ONVIF_CONFIGURATION_ENUMERATION type;
  type.size = 4;

  unsigned int arr[4] = {0, 1, 2, 3};
  type.typeArray = arr;
  char *profileToken = nullptr;

  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken, &type);
  ASSERT_THAT(err, nullopt);
  cout << "getProfiles_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, createProfile_V2)
{
  string jsonResponse;
  char name[65] = "profileName";

  auto err = onvif.createProfile_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, name);
  ASSERT_THAT(err, nullopt);
  cout << "createProfile_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getOSDs_V2)
{
  string jsonResponse;
  // char videoSourceConfigurationToken[65] = {0};
  // char OSDToken[65] = {0};
  char *videoSourceConfigurationToken = nullptr;
  char *OSDToken = nullptr;

  auto err = onvif.getOSDs_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceConfigurationToken, OSDToken);
  ASSERT_THAT(err, nullopt);
  cout << "getOSDs_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getOSDOptions_V2)
{
  string jsonResponse;
  char videoSourceConfigurationToken[65] = "VideoSourceToken";

  auto err = onvif.getOSDOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceConfigurationToken);
  ASSERT_THAT(err, nullopt);
  cout << "getOSDOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, createOSD_V2_AND_deleteOSD_V2)
{
  string jsonResponse;

  ONVIF_SET_OSD_PARAM param = {0};
  param.OSDConfigurationToken = (char *)"myOSDToken";

  // 获取VideoSourceConfigurationToken
  auto err = onvif.getVideoSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  string VideoSourceConfigurationToken = configurations[0]["token"].get<string>();

  param.videoSourceConfigurationToken = (char *)VideoSourceConfigurationToken.c_str();
  param.type = 0;
  param.positionType = 2;
  param.positionX = nullptr;
  param.positionY = nullptr;
  param.isPersistentText = nullptr;
  param.textType = 0;
  param.dateFormat = 0;
  param.timeFormat = 0;
  param.fontSize = nullptr;
  param.fontColor = nullptr;
  param.fontTransparent = nullptr;
  param.backgroundColor = nullptr;
  param.backgroundTransparent = nullptr;
  param.plainText = (char *)"my new plain text";
  param.imgPath = nullptr;

  // 创建
  err = onvif.createOSD_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看创建结果
  j = json::parse(jsonResponse);
  string configToken = j["OSDToken"].get<string>();
  err = onvif.getOSDs_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, nullptr, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "createOSD_V1 result: " << jsonResponse << endl;

  // 删除
  err = onvif.deleteOSD_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);

  err = onvif.getOSDs_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, nullptr, configToken.c_str());
  ASSERT_TRUE(err != nullopt);
}

TEST_F(onvifToolTest, setOSD_V2)
{
  string jsonResponse;

  ONVIF_SET_OSD_PARAM param = {0};
  param.OSDConfigurationToken = (char *)"myOSDToken";

  // 获取VideoSourceConfigurationToken
  auto err = onvif.getVideoSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  string VideoSourceConfigurationToken = configurations[0]["token"].get<string>();

  param.videoSourceConfigurationToken = (char *)VideoSourceConfigurationToken.c_str();
  param.type = 0;
  param.positionType = 2;
  param.positionX = nullptr;
  param.positionY = nullptr;
  param.isPersistentText = nullptr;
  param.textType = 0;
  param.dateFormat = 0;
  param.timeFormat = 0;
  param.fontSize = nullptr;
  param.fontColor = nullptr;
  param.fontTransparent = nullptr;
  param.backgroundColor = nullptr;
  param.backgroundTransparent = nullptr;
  param.plainText = (char *)"my new plain text";
  param.imgPath = nullptr;

  // 新建一个OSD
  err = onvif.createOSD_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看新建结果
  j = json::parse(jsonResponse);
  string configToken = j["OSDToken"].get<string>();
  err = onvif.getOSDs_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, nullptr, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "before set: " << jsonResponse << endl;

  // 修改
  param.OSDConfigurationToken = (char *)configToken.c_str();
  param.plainText = (char *)"set new plain text";
  err = onvif.setOSD_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  // 查看修改结果
  err = onvif.getOSDs_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, nullptr, configToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "after set: " << jsonResponse << endl;

  // 删除
  err = onvif.deleteOSD_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, configToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getMasks_V2)
{
  string jsonResponse;
  // char videoSourceConfigurationToken[65] = {0};
  // char maskToken[65] = {0};
  char *videoSourceConfigurationToken = nullptr;
  char *maskToken = nullptr;

  auto err = onvif.getMasks_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceConfigurationToken, maskToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMasks_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getMaskOptions_V2)
{
  string jsonResponse;
  char videoSourceConfigurationToken[65] = "VideoSourceToken";

  auto err = onvif.getMaskOptions_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, videoSourceConfigurationToken);
  ASSERT_THAT(err, nullopt);
  cout << "getMaskOptions_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getStreamUri_V2)
{
  string jsonResponse;

  ONVIF_TRANSPORT_PROTOCOL_V2 protocol;
  protocol.protocolsName = 0;
  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 测试getStreamUri_V2
  err = onvif.getStreamUri_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken, protocol);
  ASSERT_THAT(err, nullopt);
  cout << "getStreamUri_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getSnapshotUri_V2)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 测试getSnapshotUri_V2
  err = onvif.getSnapshotUri_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getSnapshotUri_V2: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, startMulticastStreaming_V2)
{
  string jsonResponse;
  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  err = onvif.startMulticastStreaming_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, stopMulticastStreaming_V2)
{
  string jsonResponse;
  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  err = onvif.stopMulticastStreaming_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, addConfiguration_V2)
{
  string jsonResponse;

  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 选择要修改的profile
  string profileToken = "";
  json j = json::parse(jsonResponse);
  auto profiles = j["profiles"].get<vector<json>>();
  for (int i = 0; i < (int)profiles.size(); i++)
  {
    if (profiles[i]["name"] == "profileName")
    {
      profileToken = profiles[i]["token"].get<string>();
    }
  }
  ASSERT_TRUE(profileToken != "");

  // 待添加的配置
  err = onvif.getAudioSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configurations.size() > 0);
  string configToken = "";
  configToken = configurations[0]["token"].get<string>();
  ASSERT_TRUE(configToken != "");

  ONVIF_CONFIGURATION_ENUMERATION enumeration;
  char *tokenArray[1];
  tokenArray[0] = (char *)configToken.c_str();

  unsigned int typeArray[1] = {1};

  enumeration.size = 1;
  enumeration.tokenArray = tokenArray;
  enumeration.typeArray = typeArray;

  err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);
  cout << "before set: " << jsonResponse << endl;

  // 添加
  err = onvif.addConfiguration_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);

  err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);
  cout << "after set: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, removeConfiguration_V2)
{
  string jsonResponse;

  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 选择要修改的profile
  string profileToken = "";
  json j = json::parse(jsonResponse);
  auto profiles = j["profiles"].get<vector<json>>();
  for (int i = 0; i < (int)profiles.size(); i++)
  {
    if (profiles[i]["name"] == "profileName")
    {
      profileToken = profiles[i]["token"].get<string>();
    }
  }
  ASSERT_TRUE(profileToken != "");

  // 待删除的配置
  err = onvif.getAudioSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  auto configurations = j["configurations"].get<vector<json>>();
  ASSERT_TRUE(configurations.size() > 0);
  string configToken = "";
  configToken = configurations[0]["token"].get<string>();
  ASSERT_TRUE(configToken != "");

  ONVIF_CONFIGURATION_ENUMERATION enumeration;
  char *tokenArray[1];
  tokenArray[0] = (char *)configToken.c_str();

  unsigned int typeArray[1] = {1};

  enumeration.size = 1;
  enumeration.tokenArray = tokenArray;
  enumeration.typeArray = typeArray;

  err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);
  cout << "before set: " << jsonResponse << endl;

  // 添加
  err = onvif.removeConfiguration_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);

  err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str(), &enumeration);
  ASSERT_THAT(err, nullopt);
  cout << "after set: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, deleteProfile_V2)
{
  string jsonResponse;

  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 选择要修改的profile
  string profileToken = "";
  json j = json::parse(jsonResponse);
  auto profiles = j["profiles"].get<vector<json>>();
  for (int i = 0; i < (int)profiles.size(); i++)
  {
    if (profiles[i]["name"] == "profileName")
    {
      profileToken = profiles[i]["token"].get<string>();
    }
  }
  ASSERT_TRUE(profileToken != "");

  err = onvif.deleteProfile_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD, profileToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getVideoOutputs_DeviceIO)
{
  string jsonResponse;

  auto err = onvif.getVideoOutputs_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoOutputs_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSources_DeviceIO)
{
  string jsonResponse;

  auto err = onvif.getVideoSources_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSources_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoOutputConfiguration_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getVideoOutputConfiguration_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoOutputConfiguration_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoOutputConfigurationOptions_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getVideoOutputConfigurationOptions_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getVideoSourceConfiguration_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getVideoSourceConfiguration_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfiguration_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getVideoSourceConfigurationOptions_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getVideoSourceConfigurationOptions_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getVideoSourceConfigurationOptions_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputs_DeviceIO)
{
  string jsonResponse;

  auto err = onvif.getAudioOutputs_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputs_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSources_DeviceIO)
{
  string jsonResponse;

  auto err = onvif.getAudioSources_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSources_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfiguration_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getAudioOutputConfiguration_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfiguration_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioOutputConfigurationOptions_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getAudioOutputConfigurationOptions_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioOutputConfigurationOptions_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfiguration_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getAudioSourceConfiguration_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfiguration_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getAudioSourceConfigurationOptions_DeviceIO)
{
  string jsonResponse;

  char configToken[65] = "token";

  auto err = onvif.getAudioSourceConfigurationOptions_DeviceIO(jsonResponse, DEVICEIO_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getAudioSourceConfigurationOptions_DeviceIO: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getNodes)
{
  string jsonResponse;

  auto err = onvif.getNodes(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "nodes: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getNode)
{
  string jsonResponse;

  auto err = onvif.getNodes(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  json j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);

  string nodeToken = j["nodes"][0]["token"].get<string>();
  err = onvif.getNode(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, nodeToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "node: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPTZConfigurations)
{
  string jsonResponse;

  auto err = onvif.getPTZConfigurations(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "PTZConfigurations: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPTZConfiguration)
{
  string jsonResponse;

  char configToken[65] = "00100";

  auto err = onvif.getPTZConfiguration(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getPTZConfiguration: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPTZConfigurationOptions)
{
  string jsonResponse;

  char configToken[65] = "00100";

  auto err = onvif.getPTZConfigurationOptions(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, configToken);
  ASSERT_THAT(err, nullopt);
  cout << "getConfigurationOptions: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPTZStatus_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下PTZ状态
  err = onvif.getPTZStatus(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getPTZStatus: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPTZStatus_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下PTZ状态
  err = onvif.getPTZStatus(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getPTZStatus: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, absoluteMove_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 绝对移动
  ONVIF_PTZ_MOVE_PARAM move = {0};
  move.zoomEnable = false;
  move.zoomSpace = 0;
  move.zoomVal = 0;
  move.panTiltEnable = true;
  move.panTiltSpace = 0;
  move.panPos = 0.7;
  move.tiltPos = 0.7;
  move.moveSpeed = nullptr;
  err = onvif.absoluteMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &move);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, absoluteMove_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 绝对移动
  ONVIF_PTZ_MOVE_PARAM move = {0};
  move.zoomEnable = false;
  move.zoomSpace = 0;
  move.zoomVal = 0;
  move.panTiltEnable = true;
  move.panTiltSpace = 0;
  move.panPos = 0.7;
  move.tiltPos = 0.7;
  move.moveSpeed = nullptr;
  err = onvif.absoluteMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &move);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, relativeMove_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 相对移动
  ONVIF_PTZ_MOVE_PARAM move = {0};
  move.zoomEnable = false;
  move.zoomSpace = 0;
  move.zoomVal = 0;
  move.panTiltEnable = true;
  move.panTiltSpace = 2;
  move.panPos = 0.01;
  move.tiltPos = 0.01;
  move.moveSpeed = nullptr;
  err = onvif.relativeMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &move);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, relativeMove_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 相对移动
  ONVIF_PTZ_MOVE_PARAM move = {0};
  move.zoomEnable = false;
  move.zoomSpace = 0;
  move.zoomVal = 0;
  move.panTiltEnable = true;
  move.panTiltSpace = 2;
  move.panPos = 0.01;
  move.tiltPos = 0.01;
  move.moveSpeed = nullptr;
  err = onvif.relativeMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &move);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, continuousMove_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 持续移动
  ONVIF_PTZ_SPEED_PARAM speed = {0};
  speed.panTiltSpeedEnable = true;
  speed.panSpeed = 0.01;
  speed.tiltSpeed = 0.01;
  speed.panTiltSpace = 2;
  speed.zoomSpeedEnable = false;
  speed.zoomSpace = 0;
  speed.zoomSpeed = 0;
  char *timeOut = (char *)"PT10S";
  err = onvif.continuousMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &speed, timeOut);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, continuousMove_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 持续移动
  ONVIF_PTZ_SPEED_PARAM speed = {0};
  speed.panTiltSpeedEnable = true;
  speed.panSpeed = 0.01;
  speed.tiltSpeed = 0.01;
  speed.panTiltSpace = 2;
  speed.zoomSpeedEnable = false;
  speed.zoomSpace = 0;
  speed.zoomSpeed = 0;
  char *timeOut = (char *)"PT10S";
  err = onvif.continuousMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &speed, timeOut);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, stopMove_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 停止移动
  err = onvif.stopMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, stopMove_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 停止移动
  err = onvif.stopMove(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getPresets_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getPresets: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getPresets_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  cout << "getPresets: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, gotoHomePosition_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 去往home的位置
  err = onvif.gotoHomePosition(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, gotoHomePosition_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 去往home的位置
  ONVIF_PTZ_SPEED_PARAM speed;
  speed.panTiltSpace = 1;
  speed.panTiltSpeedEnable = true;
  speed.zoomSpeedEnable = false;
  speed.zoomSpace = 0;
  speed.zoomSpeed = 0;
  speed.panSpeed = 1;
  speed.tiltSpeed = 180;
  err = onvif.gotoHomePosition(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, &speed);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setHomePosition_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 设置home的位置
  err = onvif.setHomePosition(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setHomePosition_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 设置home的位置
  err = onvif.setHomePosition(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, gotoPreset_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  string presetToken = j["preset"][0]["token"].get<string>();

  // 去往preset的位置
  err = onvif.gotoPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, gotoPreset_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  string presetToken = j["preset"][0]["token"].get<string>();

  // 去往preset的位置
  ONVIF_PTZ_SPEED_PARAM speed;
  speed.panTiltSpace = 1;
  speed.panTiltSpeedEnable = true;
  speed.zoomSpeedEnable = false;
  speed.zoomSpace = 0;
  speed.zoomSpeed = 0;
  speed.panSpeed = 1;
  speed.tiltSpeed = 180;
  err = onvif.gotoPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str(), &speed);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setPreset_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  string presetToken = j["preset"][0]["token"].get<string>();

  // 设置预置位
  err = onvif.setPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, setPreset_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 获取该媒体下的预置位
  err = onvif.getPresets(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  string presetToken = j["preset"][0]["token"].get<string>();

  // 设置预置位
  err = onvif.setPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, addPreset_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 添加预置位
  char name[65] = "presetName wzj";
  err = onvif.addPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, name);
  ASSERT_THAT(err, nullopt);
  cout << "addPreset: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, addPreset_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 添加预置位
  char name[65] = "presetName wzj";
  err = onvif.addPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, name);
  ASSERT_THAT(err, nullopt);
  cout << "addPreset: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, removePreset_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 添加预置位
  char name[65] = "presetName wzj2";
  err = onvif.addPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, name);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  string presetToken = j["presetToken"].get<string>();

  // 删除预置位
  err = onvif.removePreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, removePreset_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char profileToken[65] = {0};

  // 获取所有的profile
  auto err = onvif.getProfiles_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);

  // 获取有效的profileToken
  json j = json::parse(jsonResponse);
  ASSERT_FALSE(j["count"] == 0);
  auto profiles = j["profiles"].get<vector<json>>();
  strcpy(profileToken, profiles[0]["token"].get<string>().c_str());

  // 添加预置位
  char name[65] = "presetName wzj";
  err = onvif.addPreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, name);
  ASSERT_THAT(err, nullopt);
  j = json::parse(jsonResponse);
  string presetToken = j["presetToken"].get<string>();

  // 删除预置位
  err = onvif.removePreset(jsonResponse, PTZ_SERVICE, USER_NAME, PASSWORD, profileToken, presetToken.c_str());
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, getRecordingSummary)
{
  string jsonResponse;

  auto err = onvif.getRecordingSummary(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  cout << "getRecordingSummary: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, findRecordings)
{
  string jsonResponse;
  ONVIF_FIND_RECORDINGS_PARAM param;
  param.includeRecordingsTokenSize = 0;
  param.includeSourcesTokenSize = 0;
  param.includeRecordingsToken = nullptr;
  param.includeSourcesToken = nullptr;
  param.includeSourcesType = nullptr;
  param.recordingInformationFilter = nullptr;
  param.maxMatches = nullptr;
  param.keepAliveTime = (char *)"PT1M";

  auto err = onvif.findRecordings(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);
  cout << "findRecordings: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getRecordingInformation)
{
  string jsonResponse;
  char recordingToken[65] = "RecordMediaProfile00000";

  // 设置长一点的超时时间；
  onvif.setTimeOut(20);
  auto err = onvif.getRecordingInformation(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, recordingToken);

  ASSERT_THAT(err, nullopt);
  cout << "getRecordingInformation: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getRecordingSearchResults)
{
  string jsonResponse;
  ONVIF_FIND_RECORDINGS_PARAM param;
  // 过滤对应媒体源的例子
  // param.includeRecordingsTokenSize = 0;
  // param.includeSourcesTokenSize = 1;
  // char *token[1];
  // int *type[1];
  // int temp = 0;
  // type[0] = &temp;
  // token[0] = (char*)"MediaProfile00000";
  // param.includeRecordingsToken = nullptr;
  // param.includeSourcesToken = token;
  // param.includeSourcesType = type;

  param.includeRecordingsTokenSize = 0;
  param.includeSourcesTokenSize = 0;
  param.includeRecordingsToken = nullptr;
  param.includeSourcesToken = nullptr;
  param.includeSourcesType = nullptr;

  // 设置了filter，172.16.34.73 使用"boolean(//Track[TrackType = \"Metadata\"])"找不到记录，过滤成功
  // 但是使用"boolean(//Track[TrackType = \"Metadataadasd\"])"这样的无效的TrackType，又会把所有的结果搜索出来
  // 所以可能需要确保filter提供的查询条件的数据类型和内容要符合onvif协议，filter才会有效
  param.recordingInformationFilter = (char *)"boolean(//Track[TrackType = \"Video\"])";
  param.maxMatches = nullptr;
  param.keepAliveTime = (char *)"PT60S";

  // 获取搜索令牌
  auto err = onvif.findRecordings(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  string searchToken = j["searchToken"].get<string>();

  bool flag = true;
  do
  {
    // 获取搜索结果
    this_thread::sleep_for(chrono::seconds(5));
    err = onvif.getRecordingSearchResults(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, searchToken.c_str());
    ASSERT_THAT(err, nullopt);
    cout << "getRecordingSearchResults: " << jsonResponse << endl;
    j = json::parse(jsonResponse);
    if (j["searchState"] == "completed" || j["searchState"] == "unknown")
    {
      flag = false;
    }
  } while (flag);
}

TEST_F(onvifToolTest, endSearch)
{
  string jsonResponse;
  ONVIF_FIND_RECORDINGS_PARAM param;
  param.includeRecordingsTokenSize = 0;
  param.includeSourcesTokenSize = 0;
  param.includeRecordingsToken = nullptr;
  param.includeSourcesToken = nullptr;
  param.includeSourcesType = nullptr;
  param.recordingInformationFilter = nullptr;
  param.maxMatches = nullptr;
  param.keepAliveTime = (char *)"PT1M";

  // 获取搜索令牌
  onvif.setTimeOut(20);
  auto err = onvif.findRecordings(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  string searchToken = j["searchToken"].get<string>();

  err = onvif.endSearch(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, searchToken.c_str());
  ASSERT_THAT(err, nullopt);
  cout << "endSearch: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, getReplayUri)
{
  string jsonResponse;
  ONVIF_FIND_RECORDINGS_PARAM param;
  param.includeRecordingsTokenSize = 0;
  param.includeSourcesTokenSize = 0;
  param.includeRecordingsToken = nullptr;
  param.includeSourcesToken = nullptr;
  param.includeSourcesType = nullptr;
  param.recordingInformationFilter = nullptr;
  param.maxMatches = nullptr;
  param.keepAliveTime = (char *)"PT1M";

  // 获取搜索令牌
  onvif.setTimeOut(20);
  auto err = onvif.findRecordings(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, &param);
  ASSERT_THAT(err, nullopt);

  json j = json::parse(jsonResponse);
  string searchToken = j["searchToken"].get<string>();

  bool flag = true;
  string recordingToken = "";
  do
  {
    // 获取搜索结果
    this_thread::sleep_for(chrono::seconds(5));
    err = onvif.getRecordingSearchResults(jsonResponse, SEARCH_SERVICE, USER_NAME, PASSWORD, searchToken.c_str());
    ASSERT_THAT(err, nullopt);
    cout << "getRecordingSearchResults: " << jsonResponse << endl;
    j = json::parse(jsonResponse);
    if (j["searchState"] == "completed" || j["searchState"] == "unknown")
    {
      flag = false;
    }
    if (recordingToken == "")
    {
      if (j["recordingInformation"].get<vector<json>>().size() == 0)
      {
        continue;
      }
      recordingToken = j["recordingInformation"][0]["recordingToken"].get<string>();
    }

  } while (flag && recordingToken == "");

  ONVIF_STREAM_SETUP_PARAM setUp = {0};
  setUp.streamType = 0;
  setUp.transport.protocolsName = 0;
  setUp.transport.tunnel = nullptr;
  err = onvif.getReplayUri(jsonResponse, REPLAY_SERVICE, USER_NAME, PASSWORD, recordingToken.c_str(), &setUp);
  ASSERT_THAT(err, nullopt);
  cout << "getReplayUri: " << jsonResponse << endl;
}

TEST_F(onvifToolTest, focusMove_and_stopFocusMove_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char *videoSourceToken;

  ONVIF_FOCUS_MOVE_PARAM param;
  param.timeOut = (char *)"PT4S";
  param.direction = 1;

  auto err = onvif.getVideoSources_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  json j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  videoSourceToken = (char *)j["videoSources"][0]["token"].get<string>().c_str();

  // 修改焦距
  err = onvif.focusMove(jsonResponse, PROVISIONING_SERVICE, USER_NAME, PASSWORD, videoSourceToken, &param);
  ASSERT_THAT(err, nullopt);

  this_thread::sleep_for(chrono::seconds(2));
  // 停止
  err = onvif.stopFocusMove(jsonResponse, PROVISIONING_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, focusMove_and_stopFocusMove_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char *videoSourceToken;

  ONVIF_FOCUS_MOVE_PARAM param;
  param.timeOut = (char *)"PT4S";
  param.direction = 1;

  auto err = onvif.getVideoSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  json j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  videoSourceToken = (char *)j["configurations"][0]["sourceToken"].get<string>().c_str();

  // 修改焦距
  err = onvif.focusMove(jsonResponse, PROVISIONING_SERVICE, USER_NAME, PASSWORD, videoSourceToken, &param);
  ASSERT_THAT(err, nullopt);

  this_thread::sleep_for(chrono::seconds(2));
  // 停止
  err = onvif.stopFocusMove(jsonResponse, PROVISIONING_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, focusMove_Imaging_and_stopFocusMove_Imaging_using_MEDIA_SERVICE)
{
  string jsonResponse;

  char *videoSourceToken;

  auto err = onvif.getVideoSources_V1(jsonResponse, MEDIA_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  json j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  videoSourceToken = (char *)j["videoSources"][0]["token"].get<string>().c_str();

  // 修改焦距
  err = onvif.focusMove_Imaging(jsonResponse, IMAGING_SERVICE, USER_NAME, PASSWORD, videoSourceToken, 0.01);
  ASSERT_THAT(err, nullopt);

  this_thread::sleep_for(chrono::seconds(2));
  // 停止
  err = onvif.stopFocusMove_Imaging(jsonResponse, IMAGING_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
}

TEST_F(onvifToolTest, focusMove_Imaging_and_stopFocusMove_Imaging_using_MEDIA2_SERVICE)
{
  string jsonResponse;

  char *videoSourceToken;

  auto err = onvif.getVideoSourceConfigurations_V2(jsonResponse, MEDIA2_SERVICE, USER_NAME, PASSWORD);
  ASSERT_THAT(err, nullopt);
  json j = json::parse(jsonResponse);
  ASSERT_TRUE(j["count"] > 0);
  videoSourceToken = (char *)j["configurations"][0]["sourceToken"].get<string>().c_str();

  // 修改焦距
  err = onvif.focusMove_Imaging(jsonResponse, IMAGING_SERVICE, USER_NAME, PASSWORD, videoSourceToken, 0.01);
  ASSERT_THAT(err, nullopt);

  this_thread::sleep_for(chrono::seconds(2));
  // 停止
  err = onvif.stopFocusMove_Imaging(jsonResponse, IMAGING_SERVICE, USER_NAME, PASSWORD, videoSourceToken);
  ASSERT_THAT(err, nullopt);
}
